﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Timers;
using KC.Business.Processor;
using KC.DataAccess.Processor;
using BLL = KC.Business.Processor;
using System.Threading.Tasks;


namespace KC.Presentation.Processor
{
	public partial class Processor : ServiceBase
	{
		public Timer timer;

		public Processor()
		{
			InitializeComponent();
		}

		List<BLL.ProcessorBase> processors = null;
		ProcessorDataContext dc;


		protected override void OnStart(string[] args)
		{
			timer = new Timer();
			timer.Interval = Properties.Settings.Default.TimerInterval;
			timer.Enabled = true;
			timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
			timer.Start();
			dc = new ProcessorDataContext(System.Configuration.ConfigurationManager.ConnectionStrings["Processor"].ConnectionString);
		}

		protected override void OnStop()
		{
			timer.AutoReset = false;
			timer.Stop();
		}

		void timer_Elapsed(object sender, ElapsedEventArgs e)
		{
			timer.AutoReset = false;
			timer.Stop();

			try { RunProcessors(); }
			catch (Exception ex) { LogError(ex); }
				
			timer.AutoReset = true;
			timer.Start();
		}

		private void RunProcessors()
		{
			// First tick, new up some processors; frees up response time for onStart
			if (processors == null)
				processors = BLL.Processor.GetProcessors();

			// Every tick, do check for due runs and do due runs // a doo run run
			Parallel.ForEach(processors, processor =>
			{
				//foreach (ProcessorBase processor in processors)
				if (processor.isDue())
				{
					AddDetail(processor.GetType().Name + " due - running");
					bool result = false;
					try { result = processor.Run(); }
					catch (Exception ex) { LogError(ex); }
					AddDetail((result ? "Processor success: " : "PROCESSOR FAILURE: ") + processor.GetType().Name);

					try
					{ // update schedule for next run
						Schedule sched = (from s in dc.Schedules where s.ID == processor.schedule.ID select s).First();
						sched.NextRun = DateTime.Now + TimeSpan.FromSeconds(sched.Interval);
						dc.SubmitChanges();
						processor.schedule = sched;
					}
					catch (Exception ex)
					{
						LogError(ex);
						AddDetail("Removing " + processor.GetType().Name + " from processor list due to error.");
						processors.Remove(processor);
					}
				}
			});
		}

		protected void LogError(Exception ex)
		{
			try
			{
				dc.Errors.InsertOnSubmit(new Error() { Datetime = DateTime.Now, ExType = ex.GetType().Name, Message = ex.Message, StackTrace = ex.StackTrace ?? Environment.StackTrace });
				dc.SubmitChanges();
			}
			catch { }
		}
		protected void LogError(string ex)
		{
			try
			{
				dc.Errors.InsertOnSubmit(new Error() { Datetime = DateTime.Now, ExType = ex.GetType().Name, Message = ex, StackTrace = Environment.StackTrace });
				dc.SubmitChanges();
			}
			catch { }
		}
		protected void AddDetail(string msg)
		{
			msg = msg.Trim() + "\r\n";
			try {
				dc.Details.InsertOnSubmit(new Detail() { datetime = DateTime.Now, text = msg });
				dc.SubmitChanges(); }
			catch { }
		}

	}
}
